﻿using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Reflection;
using System.Drawing;
using System.Drawing.Design;
using System.ComponentModel.Design;
using UtfprLibrary.EntityFramework.ComponentModel;
using UtfprLibrary.Windows.Forms.ComponentModel;
using UtfprLibrary.EntityFramework.Helpers;
using UtfprLibrary.Windows.Forms.Helpers;
using UtfprLibrary.Windows.Forms.Exceptions;
using UtfprLibrary.Windows.Forms;

namespace UtfprLibrary.Windows.Forms
{
    [ToolboxItem(true)]
    //[ToolboxBitmap(typeof(ResourceFinder), "Resources.VSD_UtfprLookupField.png")]
    [Designer("UtfprLibrary.Windows.Forms.ComponentModel.UtfprLookupFieldDesigner, UtfprLibrary.WindowsForms.Design")]
    public partial class UtfprLookupField : UtfprLookupFieldBase {

        #region Fields

        bool isQueryForm = false;

        #endregion

        #region Base

        #region Data

        [Category("Data")]
        [Description("The Data Source")]
        [TypeConverter("System.Windows.Forms.Design.AdvancedBindingTypeConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
        [Editor("System.Windows.Forms.Design.DataSourceListEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override object DataSource { get; set; }

        [Category("Data")]
        [Description("The Key Member")]
        [DefaultValue("")]
        [TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
        [Editor("System.Windows.Forms.Design.DataMemberFieldEditor, System.Design", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string KeyMember { get; set; }

        [Category("Data")]
        [Description("The Lookup Source")]
        [TypeConverter("System.Windows.Forms.Design.AdvancedBindingTypeConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
        [Editor("System.Windows.Forms.Design.DataSourceListEditor, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override object LookupSource { get; set; }

        [Category("Data")]
        [Description("The Display Member")]
        [DefaultValue("")]
        [TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
        [Editor("UtfprLibrary.Windows.Forms.ComponentModel.UtfprLookupSourceDataMemberFieldEditor, UtfprLibrary.WindowsForms.Design", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string DisplayMember { get; set; }

        [Category("Data")]
        [Description("The Value Member")]
        [DefaultValue("")]
        [TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
        [Editor("UtfprLibrary.Windows.Forms.ComponentModel.UtfprLookupSourceDataMemberFieldEditor, UtfprLibrary.WindowsForms.Design", typeof(UITypeEditor))]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public override string ValueMember { get; set; }

        #endregion

        [Category("Forms")]
        [Description("Choose the query form")]
        [Editor("UtfprLibrary.Windows.Forms.ComponentModel.UtfprQueryEditor, UtfprLibrary.WindowsForms.Design", typeof(UITypeEditor))]
        public override object UtfprFormQueryType { get; set; }

        [Category("Forms")]
        [Description("Choose the crud form")]
        [Editor("UtfprLibrary.Windows.Forms.ComponentModel.UtfprCrudEditor, UtfprLibrary.WindowsForms.Design", typeof(UITypeEditor))]
        public override object UtfprFormCrudType { get; set; }

        [Category("Layout")]
        [Description("The width in pixels of the TextBox representing an EntityKey")]
        public override int KeyMemberWidth {
            get { return txtKeyMember.Width; }
            set { txtKeyMember.Width = value; }
        }

        private bool _nonNumeric = false;
        [Category("Behavior")]
        [Description("TODO")]
        public override bool NonNumeric {
            get { return _nonNumeric; }
            set { _nonNumeric = value; }
        }

        /// <summary>
        /// Retrieve the entity (populate it´s value via query by Id).
        /// </summary>
        public override void Fetch() {
            queryById();
        }

        #endregion

        #region Constructor

        public UtfprLookupField() {
            InitializeComponent();
        }

        #endregion

        #region Properties

        private bool _buttonCrudVisible = true;
        [Category("Layout")]
        [Description("")]
        public bool ButtonCrudVisible {
            get { return _buttonCrudVisible; }
            set {
                _buttonCrudVisible = value;
                btnCrud.Visible = _buttonCrudVisible;
            }
        }

        private bool _buttonQueryVisible = true;
        [Category("Layout")]
        [Description("")]
        public bool ButtonQueryVisible {
            get { return _buttonQueryVisible; }
            set {
                _buttonQueryVisible = value;
                btnQuery.Visible = _buttonQueryVisible;
            }
        }

        #region Private Properties

        private Form _utfprFormCrud;
        private Form UtfprFormCrud {
            get {
                if (UtfprFormCrudType != null && _utfprFormCrud == null) {
                    _utfprFormCrud = (Form)Activator.CreateInstance((Type)UtfprFormCrudType);
                    configUtfprFormCrud(_utfprFormCrud);
                }
                return _utfprFormCrud;
            }
        }

        private Form _utfprFormQuery;
        private Form UtfprFormQuery {
            get {
                if (UtfprFormQueryType != null && _utfprFormQuery == null) {
                    _utfprFormQuery = (Form)Activator.CreateInstance((Type)UtfprFormQueryType, new object[] { EntityDataSource.ObjectContext });
                }
                return _utfprFormQuery;
            }
        }

        private IEntityDataSource _entityDataSource;
        private IEntityDataSource EntityDataSource {
            get {
                if (_entityDataSource == null) {
                    _entityDataSource = EntityDataSourceHelper.findDataSource(this.FindForm()).EntityDataSource;
                }
                return _entityDataSource;
            }
        }

        private Type _entityType;
        private Type EntityType {
            get {
                if (_entityType == null) {
                    _entityType = (Type)((BindingSource)DataSource).DataSource;
                }
                return _entityType;
            }
        }

        #endregion

        #endregion

        #region EventHandlers

        protected override void OnLoad(EventArgs e) {
            base.OnLoad(e);

            string nameParentBase = ParentForm.GetType().BaseType.FullName;
            string queryTypeFullName = "UtfprLibrary.Windows.Forms.UtfprFormQueryBase";

            // Verifica se o form onde o Lookup aplicado é form de consulta
            if (nameParentBase == queryTypeFullName) {
                isQueryForm = true;
            }

            if (UtfprControlBase.IsInDesignMode) {
                string baseTypeFullName = "UtfprLibrary.Windows.Forms.UtfprFormCrudBase";
                string name = (Container as IDesignerHost).RootComponent.GetType().FullName;
                //if (name != baseTypeFullName) {
                //    throw new ArgumentException("UtfprLookupField is supported just in UtfprCrudBase Form Types");
                //}
            } else {
                if (LookupSource != null) {

                    // Verifica se o form onde o Lookup aplicado é form de consulta
                    if (isQueryForm) {
                        // Como está em consulta, os DataBindings são resetados
                        txtFieldMember.DataBindings.Clear();
                        txtKeyMember.DataBindings.Clear();
                    }

                    try {
                        txtFieldMember.DataBindings.Add("Text", LookupSource, DisplayMember);
                    } catch {
                        throw new ArgumentException("CannotBindProperty: " + DisplayMember);
                    }

                    try {
                        txtKeyMember.DataBindings.Add("Text", LookupSource, ValueMember);
                    } catch {
                        throw new ArgumentException("CannotBindProperty: " + ValueMember);
                    }
                }
            }

            if (ButtonCrudVisible) {
                tlpContent.ColumnStyles[1].Width = 30;
            } else {
                tlpContent.ColumnStyles[1].Width = 0;
            }

            if (ButtonQueryVisible) {
                tlpContent.ColumnStyles[2].Width = 30;
            } else {
                tlpContent.ColumnStyles[2].Width = 0;
            }


            txtKeyMember.TextChanged += (sender, args) => {
                if (txtKeyMember.Text == "0") {
                    txtKeyMember.Text = "";
                }
            };
        }

        private void txtKeyMember_Leave(object sender, EventArgs e) {
            queryById();
        }

        private void txtKeyMember_KeyPress(object sender, KeyPressEventArgs e) {
            //call the queryById when the enter key is pressed
            if (e.KeyChar == (char)Keys.Enter) {
                e.Handled = false;
                if (DataSource != null) {
                    if (this.ActiveControl != null) {
                        this.SelectNextControl(this.ActiveControl, true, true, true, true);
                    }
                }
                return;
            }

            if (e.KeyChar == (char)Keys.Back) {
                return;
            }

            if (!NonNumeric) {
                //blocks the non numeric characters
                if (!System.Text.RegularExpressions.Regex.IsMatch(e.KeyChar.ToString(), "\\d+")) {
                    e.Handled = true;
                }
            }
        }

        private void btnCrud_Click(object sender, EventArgs e) {
            try {
                //init UtfprFormCrud property preventing a NullReferenceException
                var foo = UtfprFormCrud;
            } catch { }

            if (UtfprFormCrud != null) {
                if (UtfprFormCrud.ShowDialog() == DialogResult.OK) {
                    try {
                        //object currentEntity = UtfprBindingNavigatorHelper
                        //    .findRootSourceNavigator(UtfprFormCrud)
                        //    .BindingSource.Current;
                        object currentEntity = UtfprBindingNavigatorBaseHelper
                            .findRootSourceNavigator(UtfprFormCrud)
                            .CurrentItem;
                        updateLookupSourceCurrent(currentEntity);
                    } catch (Exception ex) {
                        throw new UtfprWFControlsException("", ex);
                    }
                }
            } else {
                MessageBox.Show("Nenhum formulário de cadastro foi configurado.");
            }
        }

        private void btnCrud_VisibleChanged(object sender, EventArgs e) {
            if (ButtonCrudVisible) {
                tlpContent.ColumnStyles[1].Width = 30;
            } else {
                tlpContent.ColumnStyles[1].Width = 0;
            }
        }

        private void btnQuery_Click(object sender, EventArgs e) {
            if (UtfprFormQuery != null) {
                if (UtfprFormQuery.ShowDialog() == DialogResult.OK) {
                    try {
                        object currentEntity = UtfprFormQuery
                            .GetType()
                            .GetProperty("CurrentEntity")
                            .GetValue(UtfprFormQuery, null);
                        updateLookupSourceCurrent(currentEntity);
                    } catch (Exception ex) {
                        throw new UtfprWFControlsException("", ex);
                    }
                }
            } else {
                MessageBox.Show("Nenhum formulário de consulta foi configurado.");
            }
        }
        
        private void btnQuery_VisibleChanged(object sender, EventArgs e) {
            if (ButtonQueryVisible) {
                tlpContent.ColumnStyles[2].Width = 30;
            } else {
                tlpContent.ColumnStyles[2].Width = 0;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// TODO
        /// </summary>
        private void configUtfprFormCrud(Form form) {
            form.Height += 27;
            var flags = BindingFlags.NonPublic | BindingFlags.Instance;
            var tlpFormInfo = form.GetType().GetField("tlpForm", flags);
            var tlpForm = (TableLayoutPanel)tlpFormInfo.GetValue(form);
            tlpForm.RowCount++;
            tlpForm.RowStyles.Add(new RowStyle(SizeType.Absolute, 5F));
            tlpForm.RowStyles[5].SizeType = SizeType.AutoSize;
            tlpForm.RowStyles[5].Height = 0F;

            var btnCancel = new Button();
            btnCancel.DialogResult = DialogResult.Cancel;
            btnCancel.Size = new Size(75, 23);
            btnCancel.Text = "Cancelar";
            btnCancel.UseVisualStyleBackColor = true;

            var btnOK = new Button();
            btnOK.DialogResult = DialogResult.OK;
            btnOK.Name = "btnOK";
            btnOK.Size = new Size(75, 23);
            btnOK.Text = "OK";
            btnOK.UseVisualStyleBackColor = true;

            var flpOkCancel = new FlowLayoutPanel();
            flpOkCancel.Controls.Add(btnCancel);
            flpOkCancel.Controls.Add(btnOK);
            flpOkCancel.Dock = DockStyle.Fill;
            flpOkCancel.FlowDirection = FlowDirection.RightToLeft;
            flpOkCancel.AutoSize = true;
            flpOkCancel.AutoSizeMode = AutoSizeMode.GrowAndShrink;
            tlpForm.Controls.Add(flpOkCancel, 1, 5);
        }

        /// <summary>
        /// TODO
        /// </summary>
        private void updateLookupSourceCurrent(object entity) {
            BindingSource lookup = LookupSource as BindingSource;

            if (lookup.Current == null || isQueryForm) {
                lookup.List.Clear();
                lookup.List.Add(entity);
            }

            if (entity == null) {
                try {
                    lookup.Current.GetType().GetProperty(ValueMember).SetValue(lookup.Current, null, null);
                    lookup.CurrencyManager.Refresh();
                } catch (Exception ex) {
                    throw ex;
                }
            } else {
                try {
                    var entityID = isQueryForm ? entity.GetType().GetProperty(ValueMember).GetValue(entity, null) : entity.GetType().GetProperty(KeyMember).GetValue(entity, null);
                    
                    lookup.Current.GetType().GetProperty(ValueMember).SetValue(lookup.Current, entityID, null);
                    lookup.CurrencyManager.Refresh();
                } catch (Exception ex) {
                    throw ex;
                }
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        private void queryById() {
            if (txtKeyMember.Text.Trim() == string.Empty || txtKeyMember.Text.Trim() == "0") {
                try {
                    updateLookupSourceCurrent(null);
                } catch (Exception ex) {
                    throw new UtfprWFControlsException("", ex);
                }
            } else {
                object id = null;

                if (NonNumeric) {
                    id = txtKeyMember.Text;
                } else {
                    id = int.Parse(txtKeyMember.Text);
                }

                try {
                    object currentObject = EntityDataSource.FindById(EntityType, id, FetchModeEnum.Lazy, null);
                    updateLookupSourceCurrent(currentObject);
                } catch (Exception ex) {
                    throw new UtfprWFControlsException("", ex);
                }

            }
        }

        #endregion
    }
}